package ctx

import (
	"context"
	"time"
)

type Ctx struct {
	ctx    context.Context
	cancel context.CancelFunc
}

func (this Ctx) Close() {
	if this.cancel != nil {
		this.cancel()
	}
}

func (this Ctx) Ctx() context.Context {
	return this.ctx
}

func (this Ctx) Done() <-chan struct{} {
	return this.Ctx().Done()
}

func (this Ctx) Err() error {
	return this.Ctx().Err()
}

func (this Ctx) Value(key interface{}) interface{} {
	return this.Ctx().Value(key)
}

func (this Ctx) Deadline() (deadline time.Time, ok bool) {
	return this.Ctx().Deadline()
}

func (this Ctx) Set(key, value interface{}) {
	context.WithValue(this.Ctx(), key, value)
}

func getParent(parent ...context.Context) context.Context {
	if len(parent) > 0 && parent[0] != nil {
		return parent[0]
	}
	return context.Background()
}

func New() context.Context {
	return context.Background()
}

func WithCancel(parent ...context.Context) Ctx {
	c := Ctx{}
	c.ctx, c.cancel = context.WithCancel(getParent(parent...))
	return c
}

func WithDeadline(d time.Time, parent ...context.Context) Ctx {
	c := Ctx{}
	c.ctx, c.cancel = context.WithDeadline(getParent(parent...), d)
	return c
}

func WithTimeout(timeout time.Duration, parent ...context.Context) Ctx {
	c := Ctx{}
	c.ctx, c.cancel = context.WithTimeout(getParent(parent...), timeout)
	return c
}
